package com.cloudoer.blog.aspect;

import com.cloudoer.blog.exception.ControllerException;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @Aspect
 * 作用是把当前类标识为一个切面供容器读取
 *
 * @Before
 * 标识一个前置增强方法，相当于BeforeAdvice的功能
 *
 * @AfterReturning
 * 后置增强，相当于AfterReturningAdvice，方法退出时执行
 *
 * @AfterThrowing
 * 异常抛出增强，相当于ThrowsAdvice
 *
 * @After
 * final增强，不管是抛出异常或者正常退出都会执行
 *
 * @Around
 * 环绕增强，相当于MethodIntercepto
 */

/**
 * 日志切面类
 */
@Aspect
@Component
public class LogAspect {
    private static Logger logger = LoggerFactory.getLogger(LogAspect.class);

    /**
     *  1、execution(): 表达式主体。
     *
     *  2、第一个*号：表示返回类型，*号表示所有的类型。
     *
     *  3、包名：表示需要拦截的包名，后面的两个句点表示当前包和当前包的所有子包，com.cloudoer.blog.controller包、子孙包下所有类的方法。
     *
     *  4、第二个*号：表示类名，*号表示所有的类。
     *
     *  5、*(..):最后这个星号表示方法名，*号表示所有的方法，后面括弧里面表示方法的参数，两个句点表示任何参数。
     */
    @Pointcut("execution(public * com.cloudoer.blog.controller..*.*(..))")
    public void webLog(){}

    /*@Pointcut("@annotation(com.cloudoer.blog.annotation.AddIdAnnotation)")
    public void webLog(){}*/

    /*@Before("webLog()")
    public void deBefore(JoinPoint joinPoint) throws Throwable {

    }

    @AfterReturning(returning = "ret", pointcut = "webLog()")
    public void doAfterReturning(Object ret) throws Throwable {
        // 处理完请求，返回内容
        System.out.println("方法的返回值 : " + ret);
    }

    //后置异常通知
    @AfterThrowing("webLog()")
    public void throwss(JoinPoint jp){
        System.out.println("方法异常时执行.....");
    }

    //后置最终通知,final增强，不管是抛出异常或者正常退出都会执行
    @After("webLog()")
    public void after(JoinPoint jp){
        System.out.println("方法最后执行.....");
    }*/

    //环绕通知,环绕增强，相当于MethodInterceptor
    @Around("webLog()")
    public Object around(ProceedingJoinPoint pjp) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        HttpServletResponse response = attributes.getResponse();
        try {
            long start = new Date().getTime();
            logger.info("|-------------------------------"+new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.ms").format(start)+"-------------------------------|");
            logger.info("URL : " + request.getRequestURL().toString());
            logger.info("HTTP_METHOD : " + request.getMethod());
            logger.info("IP : " + request.getRemoteAddr());
            logger.info("CLASS_METHOD : " + pjp.getSignature().getDeclaringTypeName() + "." + pjp.getSignature().getName());
            logger.info("ARGS : " + Arrays.toString(pjp.getArgs()));
            Object o =  pjp.proceed();
            long end = new Date().getTime();
            logger.info("success,time consuming:" + (end - start) + "ms");
            return o;
        } catch (Throwable e) {
            logger.error("error，message：" + e.getMessage());
            //response.setStatus(500);
            //response.setHeader("message", e.getMessage());
            //return null;
            throw new ControllerException(e.getMessage());
        }
    }
}
